use rand::Rng;

fn main() {
    println!("Hello, world!");
    let mut rng = rand::thread_rng();
    let ran = rng.gen_range(0..=100) as i32;
    println!("Random number: {}", ran);
    test_match_at(ran);

    let rany = rng.gen_range(0..=100) as i32;
    describe_point(ran, rany);

    let ranx = rng.gen_range(-100..=10) as i32;
    let rany = rng.gen_range(-100..=10) as i32;
    describe_points(ranx, rany);

    let ranx = rng.gen_range(-1..=1) as i32;
    let rany = rng.gen_range(-1..=1) as i32;
    let point = Point { x: ranx, y: rany };
    describe_point_struct(point);
    let ranx = rng.gen_range(-1..=1) as i32;
    let rany = rng.gen_range(-1..=1) as i32;
    let point = Point { x: ranx, y: rany };
    describe_point_struct2(point);

    match_array();
    match_str(&[]);
    match_str(&["ab", "cd","ef"]);
    match_str(&["a"]);
    match_str(&["a", "b", "c", "d", "e"]);

    let point = rng.gen_range(0..=10) as i32;
    match_guard(Some(point));
}

/// 使用match匹配模式的定义， 特别是对@符号的使用规则 
fn test_match_at(num: i32) {
    match num {
        1 => println!("One"),
        2 => println!("Two"),
        3 => println!("Three"),
        val @ 4..=7 => println!("Four to seven: {}", val),
        n @ _ => println!("Something else, n={}", n),
    }
}

/// 使用元组型模式与结构体模式进行匹配
fn describe_point(x: i32, y: i32) {
    match (x, y) {
        (12, 12) => println!("Origin"),
        (13, _) => println!("x axis"),
        (_, 25) => println!("y axis"),
        (x, y) => println!("({},{})", x, y),
    }
}

fn describe_points(x: i32, y: i32) {
    use std::cmp::Ordering;
    match (x.cmp(&0), y.cmp(&0)) {
        (Ordering::Equal, Ordering::Equal) => println!("Origin"),
        (Ordering::Equal, _) => println!("x axis"),
        (_, Ordering::Equal) => println!("y axis"),
        (Ordering::Greater, Ordering::Greater) => println!("Quadrant I"),
        (Ordering::Less, Ordering::Greater) => println!("Quadrant II"),
        (Ordering::Less, Ordering::Less) => println!("Quadrant III"),
        _ => println!("({},{})", x, y),
    }
}

// 结构体模式匹配
struct Point {
    x: i32,
    y: i32,
}

fn describe_point_struct(point: Point) {
    match point {
        Point { x: 0, y: 0 } => println!("Origin"),
        Point { x, y: 0 } => println!("y axis, x={}", x),
        Point { x: 0, y: height } => println!("y axis, height={}", height),
        Point { x: 1,.. } => println!("({},{})", point.x, point.y),
        Point { x: x1, y: y1 } => println!("({},{})", x1, y1),
    }
}

fn describe_point_struct2(point: Point) {
    match point {
        p @ Point { .. } => println!("Origin = ({},{})", p.x, p.y),
        // _ => println!("Something else"),
    }
}


// 匹配数组
fn match_array() {
    let arr = [1, 2, 3, 4, 5];
    match arr {
        [1, _, _, _, _] => println!("Starts with 1"),
        [a, b, c, d, e] => println!("a={}, b={}, c={}, d={}, e={}", a, b, c, d, e),
    }
}

fn match_str(name : &[&str]) {
    match name {
        [] => println!("Empty"),
        [a] => println!("a={}", a),
        [a, b] => println!("a={}, b={}", a, b),
        [a, .., b] => println!("a from {}, b to {}", a, b),
    }
}

// 守卫匹配模式
fn match_guard(num: Option<i32>) {
    match num {
        Some(x) if x < 5 => println!("{} Less than 5", x),
        Some(x) => println!("p = {}", x),
        None => println!("None"),
    }
}